package com.brodong.animal_remake.common.entities.monster.realization;

import com.brodong.animal_remake.common.skills.Blindness.SkillBlindnessSpellGoal;
import com.brodong.animal_remake.common.skills.Currentskills;
import com.brodong.animal_remake.common.skills.HaveSkill;
import com.brodong.animal_remake.common.skills.Mirror.MirrorSkillGoal;
import com.brodong.animal_remake.common.skills.SkillCastingSpellGoal;
import com.brodong.animal_remake.common.skills.SkillEvokerAttack.SkillEvokerAttackSpellGoal;
import com.brodong.animal_remake.common.skills.SkillSummon.SkillSummonSpellGoal;
import com.brodong.animal_remake.common.skills.SkillWololo.SkillWololo;
import com.brodong.animal_remake.common.skills.SkillWololo.SkillWololoSpellGoal;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.RandomStrollGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.animal.IronGolem;
import net.minecraft.world.entity.animal.Sheep;
import net.minecraft.world.entity.monster.Illusioner;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.monster.RangedAttackMob;
import net.minecraft.world.entity.npc.AbstractVillager;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;

import javax.annotation.Nullable;

public class SkillBasicEntity extends Monster implements IAnimatable,RangedAttackMob, HaveSkill, SkillWololo {
    //定义一个动画事件处理器
    private AnimationFactory factory = new AnimationFactory(this);
    private Sheep wololoTarget;
    public boolean IsBabySkill;
    public boolean playAttackAnimation = false;
    public int attackTick=1;
    //枚举攻击状态
    public static final EntityDataAccessor<Integer> STATE = SynchedEntityData.defineId(SkillBasicEntity.class, EntityDataSerializers.INT);
    private static final EntityDataAccessor<Byte> DATA_SPELL_CASTING_ID = SynchedEntityData.defineId(SkillBasicEntity.class, EntityDataSerializers.BYTE);
    public int spellCastingTickCount;
    private int clientSideIllusionTicks;
    private final Vec3[][] clientSideIllusionOffsets;
    private Currentskills skill = Currentskills.NONE;

    public SkillBasicEntity(EntityType<? extends Monster> type, Level worldIn) {
        super(type, worldIn);
        this.setBaby(worldIn.getRandom().nextFloat()<0.05F);
        this.clientSideIllusionOffsets = new Vec3[2][4];
        for(int i = 0; i < 4; ++i) {
            this.clientSideIllusionOffsets[0][i] = Vec3.ZERO;
            this.clientSideIllusionOffsets[1][i] = Vec3.ZERO;
        }
    }
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.define(STATE, 0);
        this.entityData.define(DATA_SPELL_CASTING_ID, (byte)0);
    }
    //保存数据
    public void addAdditionalSaveData(CompoundTag p_34319_) {
        super.addAdditionalSaveData(p_34319_);
        p_34319_.putBoolean("IsBaby", this.isBaby());
        p_34319_.putInt("SpellTicks", this.spellCastingTickCount);
    }
    //读取数据
    public void readAdditionalSaveData(CompoundTag p_34305_) {
        super.readAdditionalSaveData(p_34305_);
        this.setBaby(p_34305_.getBoolean("IsBaby"));
        this.spellCastingTickCount = p_34305_.getInt("SpellTicks");
    }
    //初始自带装备
    @Override
    protected void populateDefaultEquipmentSlots(DifficultyInstance p_32136_) {
        super.populateDefaultEquipmentSlots(p_32136_);
        this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.BOW));
    }
    //出生设置
    public SpawnGroupData finalizeSpawn(ServerLevelAccessor p_32146_, DifficultyInstance p_32147_, MobSpawnType p_32148_, @Nullable SpawnGroupData p_32149_, @Nullable CompoundTag p_32150_) {
        p_32149_ = super.finalizeSpawn(p_32146_, p_32147_, p_32148_, p_32149_, p_32150_);
        this.populateDefaultEquipmentSlots(p_32147_);
        this.populateDefaultEquipmentEnchantments(p_32147_);
        return p_32149_;
    }
    protected void registerGoals() {
        super.registerGoals();
        this.goalSelector.addGoal(0, new FloatGoal(this));
        this.goalSelector.addGoal(1, new SkillCastingSpellGoal(this));
        this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6D, 1.0D));
        this.goalSelector.addGoal(4, new SkillSummonSpellGoal(this));
        this.goalSelector.addGoal(5, new SkillEvokerAttackSpellGoal(this,20,20,20));
        this.goalSelector.addGoal(6, new SkillWololoSpellGoal(this));
        this.goalSelector.addGoal(7, new MirrorSkillGoal(this));
        this.goalSelector.addGoal(8, new SkillBlindnessSpellGoal(this));
        this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D));
        this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F));
        this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
        this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)));
        this.targetSelector.addGoal(2, (new NearestAttackableTargetGoal<>(this, Player.class, true)).setUnseenMemoryTicks(300));
        this.targetSelector.addGoal(3, (new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)).setUnseenMemoryTicks(300));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, false));
    }

    public static AttributeSupplier.Builder prepareAttributes() {
        return Monster.createMonsterAttributes()
                .add(Attributes.MAX_HEALTH, 300.0D).
                add(Attributes.MOVEMENT_SPEED, (double)0.32F).
                add(Attributes.ATTACK_DAMAGE, 5.5D);
//        return Monster.createMonsterAttributes().
//                add(Attributes.FOLLOW_RANGE, 35.0D).
//                add(Attributes.MOVEMENT_SPEED, (double)0.23F).
//                add(Attributes.ATTACK_DAMAGE, 3.0D).
//                add(Attributes.ARMOR, 2.0D).
//                add(Attributes.SPAWN_REINFORCEMENTS_CHANCE);
//        return Monster.createMonsterAttributes().
//                add(Attributes.MOVEMENT_SPEED, 0.5D).
//                add(Attributes.FOLLOW_RANGE, 12.0D).
//                add(Attributes.MAX_HEALTH, 24.0D);
    }
    //结盟设定
    public boolean isAlliedTo(Entity p_32665_) {
        if (p_32665_ == null) {
            return false;
        } else if (p_32665_ == this) {
            return true;
        } else if (super.isAlliedTo(p_32665_)) {
            return true;
            //和自己的恼鬼结盟
        } else if (p_32665_ instanceof FlyMeleeBasicEntity) {
            return this.isAlliedTo(((FlyMeleeBasicEntity)p_32665_).getOwner());
        } else {
            return false;
        }
    }
    public AABB getBoundingBoxForCulling() {
        return this.getBoundingBox().inflate(3.0D, 0.0D, 3.0D);
    }
    public Vec3[] getSkillOffsets(float p_32940_) {
        if (this.clientSideIllusionTicks <= 0) {
            return this.clientSideIllusionOffsets[1];
        } else {
            double d0 = (double)(((float)this.clientSideIllusionTicks - p_32940_) / 3.0F);
            d0 = Math.pow(d0, 0.25D);
            Vec3[] avec3 = new Vec3[4];
            for(int i = 0; i < 4; ++i) {
                avec3[i] = this.clientSideIllusionOffsets[1][i].scale(1.0D - d0).add(this.clientSideIllusionOffsets[0][i].scale(d0));
            }
            return avec3;
        }
    }
    //ai循环
    public void aiStep() {
        super.aiStep();
        if (this.level.isClientSide && this.isInvisible()) {
            --this.clientSideIllusionTicks;
            if (this.clientSideIllusionTicks < 0) {
                this.clientSideIllusionTicks = 0;
            }
            if (this.hurtTime != 1 && this.tickCount % 1200 != 0) {
                if (this.hurtTime == this.hurtDuration - 1) {
                    this.clientSideIllusionTicks = 3;
                    for(int k = 0; k < 4; ++k) {
                        this.clientSideIllusionOffsets[0][k] = this.clientSideIllusionOffsets[1][k];
                        this.clientSideIllusionOffsets[1][k] = new Vec3(0.0D, 0.0D, 0.0D);
                    }
                }
            } else {
                this.clientSideIllusionTicks = 3;
                float f = -6.0F;
                int i = 13;
                for(int j = 0; j < 4; ++j) {
                    this.clientSideIllusionOffsets[0][j] = this.clientSideIllusionOffsets[1][j];
                    this.clientSideIllusionOffsets[1][j] = new Vec3((double)(-6.0F + (float)this.random.nextInt(13)) * 0.5D, (double)Math.max(0, this.random.nextInt(6) - 4), (double)(-6.0F + (float)this.random.nextInt(13)) * 0.5D);
                }
                for(int l = 0; l < 16; ++l) {
                    this.level.addParticle(ParticleTypes.CLOUD, this.getRandomX(0.5D), this.getRandomY(), this.getZ(0.5D), 0.0D, 0.0D, 0.0D);
                }
                this.level.playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.ILLUSIONER_MIRROR_MOVE, this.getSoundSource(), 1.0F, 1.0F, false);
            }
        }

    }
    protected void customServerAiStep() {
        super.customServerAiStep();
        RemoveSkillTick();
    }
    public void tick() {
        super.tick();
        AddParticle();
    }
    //该状态播放器控制生物平时的各种动作
    private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
        //生物在移动，就播放移动的动画，路径和第2步的动作字符串对应
        if (event.isMoving()) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.model.move", true));
            return PlayState.CONTINUE;
        }
        //不动的话就播放闲置时的动画
        event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.model.base", true));
        return PlayState.CONTINUE;
    }

    //该状态播放器控制生物攻击时的各种动作
    private <E extends IAnimatable> PlayState predicate1(AnimationEvent<E> event) {
        //如果生物攻击状态为1并且没有死亡，就执行这个攻击动画
        if (this.entityData.get(STATE) == 1 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.model.atk1", true));
            return PlayState.CONTINUE;
        }
        return PlayState.STOP;
    }
    //将我们之前的所有动画控制器进行注册
    @Override
    public void registerControllers(AnimationData data) {
        data.addAnimationController(new AnimationController(this, "controller",
                0, this::predicate));
        data.addAnimationController(new AnimationController(this, "controller1",
                0, this::predicate1));
    }

    @Override
    public AnimationFactory getFactory() {
        // TODO Auto-generated method stub
        return this.factory;
    }

    //生物实体声音
    @Nullable
    protected SoundEvent getAmbientSound() {
        return SoundEvents.EVOKER_AMBIENT;
    }

    protected SoundEvent getDeathSound() {
        return SoundEvents.EVOKER_DEATH;
    }

    protected SoundEvent getHurtSound(DamageSource p_32654_) {
        return SoundEvents.EVOKER_HURT;
    }

    protected SoundEvent getStepSound() {
        return SoundEvents.SKELETON_STEP;
    }

    public SoundEvent getCastingSoundEvent(){
        return SoundEvents.EVOKER_CAST_SPELL;
    }

    //baby
    public boolean isBaby() {
        return IsBabySkill;
    }
    public void setBaby(boolean a){
        IsBabySkill=a;
    }
    //攻击阶段
    public int getAttckingState() {
        return this.entityData.get(STATE);
    }
    public void setAttackingState(int time) {
        this.entityData.set(STATE, time);
    }
    //远程攻击
    public void performRangedAttack(LivingEntity p_32141_, float p_32142_) {
        ItemStack itemstack = this.getProjectile(this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, item -> item instanceof net.minecraft.world.item.BowItem)));
        AbstractArrow abstractarrow = this.getArrow(itemstack, p_32142_);
        if (this.getMainHandItem().getItem() instanceof net.minecraft.world.item.BowItem)
            abstractarrow = ((net.minecraft.world.item.BowItem)this.getMainHandItem().getItem()).customArrow(abstractarrow);
        double d0 = p_32141_.getX() - this.getX();
        double d1 = p_32141_.getY(0.3333333333333333D) - abstractarrow.getY();
        double d2 = p_32141_.getZ() - this.getZ();
        double d3 = Math.sqrt(d0 * d0 + d2 * d2);
        //16F是箭速度，直接决定伤害
        abstractarrow.shoot(d0, d1 + d3 * (double)0.2F, d2, 16F, (float)(14 - this.level.getDifficulty().getId() * 4));
        this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F));
        this.level.addFreshEntity(abstractarrow);
    }
    protected AbstractArrow getArrow(ItemStack p_32156_, float p_32157_) {
        return ProjectileUtil.getMobArrow(this, p_32156_, p_32157_);
    }
    //近战攻击
    public boolean doHurtTarget(Entity entityIn) {
        if(!super.doHurtTarget(entityIn))
        {
            this.playAttackAnimation=false;
            return false;
        }
        else{
            if(entityIn instanceof LivingEntity)
            {
                float f = this.level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty();
                ((LivingEntity)entityIn).addEffect(new MobEffectInstance(MobEffects.WITHER, 100 * (int)f,0,true,true));
            }
            return true;
        }
    }
    //检测施法
    public boolean isCastingSpell() {
        if (this.level.isClientSide) {
            return this.entityData.get(DATA_SPELL_CASTING_ID) > 0;
        } else {
            return this.spellCastingTickCount > 0;
        }
    }
    //设置正在施法
    public void setIsCastingSpell(Currentskills p_33728_) {
        this.skill = p_33728_;
        this.entityData.set(DATA_SPELL_CASTING_ID, (byte)p_33728_.id);
    }
    //获取当前法术
    public Currentskills getCurrentSpell() {
        return !this.level.isClientSide ? this.skill : Currentskills.byId(this.entityData.get(DATA_SPELL_CASTING_ID));
    }
    //获取施法时间
    public int getSpellCastingTime() {
        return this.spellCastingTickCount;
    }
    //减少施法时间
    public void RemoveSkillTick(){
        if (this.spellCastingTickCount > 0) {
            --this.spellCastingTickCount;
        }
    }
    //添加施法粒子
    public void AddParticle(){
        if (this.level.isClientSide && this.isCastingSpell()) {
            Currentskills Currentskills$skill = this.getCurrentSpell();
            double d0 = Currentskills$skill.spellColor[0];
            double d1 = Currentskills$skill.spellColor[1];
            double d2 = Currentskills$skill.spellColor[2];
            float f = this.yBodyRot * ((float)Math.PI / 180F) + Mth.cos((float)this.tickCount * 0.6662F) * 0.25F;
            float f1 = Mth.cos(f);
            float f2 = Mth.sin(f);
            this.level.addParticle(ParticleTypes.ENTITY_EFFECT, this.getX() + (double)f1 * 0.6D, this.getY() + 1.8D, this.getZ() + (double)f2 * 0.6D, d0, d1, d2);
            this.level.addParticle(ParticleTypes.ENTITY_EFFECT, this.getX() - (double)f1 * 0.6D, this.getY() + 1.8D, this.getZ() - (double)f2 * 0.6D, d0, d1, d2);
        }
    }
    //变羊术
    public void setWololoTarget(@Nullable Sheep p_32635_) {
        this.wololoTarget = p_32635_;
    }
    @Nullable
    public Sheep getWololoTarget() {
        return this.wololoTarget;
    }
}